#pragma once

#include "BoundShaderStateCache.h"

namespace RenderSystem
{
	/**
	* Combined shader state and vertex definition for rendering geometry. 
	* Each unique instance consists of a vertex decl, vertex shader, and pixel shader.
	*/
	class FD3D9BoundShaderState : public Common::FRefCountedObject, public TFDynamicRHIResource<RRT_BoundShaderState>
	{
	public:

		FCachedBoundShaderStateLink CacheLink;

		Common::TRefCountPtr<IDirect3DVertexDeclaration9> VertexDeclaration;
		Common::TRefCountPtr<IDirect3DVertexShader9> VertexShader;
		Common::TRefCountPtr<IDirect3DPixelShader9> PixelShader;

		/** Initialization constructor. */
		FD3D9BoundShaderState(
			FVertexDeclarationRHIParamRef InVertexDeclarationRHI,
			DWORD* InStreamStrides,
			FVertexShaderRHIParamRef InVertexShaderRHI,
			FPixelShaderRHIParamRef InPixelShaderRHI
			);

		/**
		* Equality is based on vertex decl, vertex shader and pixel shader
		* @param Other - instance to compare against
		* @return TRUE if equal
		*/
		bool operator==(const FD3D9BoundShaderState& Other) const
		{
			return (VertexDeclaration == Other.VertexDeclaration && VertexShader == Other.VertexShader && PixelShader == Other.PixelShader);
		}

		/**
		* Get the hash for this type
		* @param Key - struct to hash
		* @return dword hash based on type
		*/
		friend DWORD GetTypeHash(const FD3D9BoundShaderState& Key)
		{
			return Common::PointerHash(
				(IDirect3DVertexDeclaration9*)Key.VertexDeclaration, 
				Common::PointerHash((IDirect3DVertexShader9 *)Key.VertexShader, 
				Common::PointerHash((IDirect3DPixelShader9 *)Key.PixelShader))
				);
		}
	};

	// Textures.
	template<typename D3DResourceType,ERHIResourceTypes ResourceTypeEnum>
	class TD3D9Texture : public Common::FRefCountedObject, public Common::TRefCountPtr<D3DResourceType>, public TFDynamicRHIResource<ResourceTypeEnum>
	{
	public:

		TD3D9Texture(bool bInSRGB = FALSE,bool bInDynamic = FALSE,D3DResourceType* InResource = NULL)
			: TRefCountPtr<D3DResourceType>(InResource)
			, bSRGB(bInSRGB) 
			, bDynamic(bInDynamic)
		{
		}

		// Accessors
		bool IsSRGB() const
		{
			return bSRGB; 
		}
		bool IsDynamic() const
		{ 
			return bDynamic;
		}

	private:
		bool bSRGB;
		bool bDynamic;
	};

	/** This represents a vertex shader that hasn't been combined with a specific declaration to create a bound shader. */
	class FD3D9OcclusionQuery : public Common::FRefCountedObject, public TFDynamicRHIResource<RRT_OcclusionQuery>
	{
	public:

		/** The query resource. */
		Common::TRefCountPtr<IDirect3DQuery9> Resource;

		/** The cached query result. */
		DWORD Result;

		/** TRUE if the query's result is cached. */
		bool bResultIsCached : 1;

		/** Initialization constructor. */
		FD3D9OcclusionQuery(IDirect3DQuery9* InResource):
		Resource(InResource),
			bResultIsCached(FALSE)
		{}
	};

	typedef TD3D9Texture<IDirect3DBaseTexture9,RRT_Texture>		FD3D9Texture;
	typedef TD3D9Texture<IDirect3DTexture9,RRT_Texture2D>		FD3D9Texture2D;
	typedef TD3D9Texture<IDirect3DCubeTexture9,RRT_TextureCube>	FD3D9TextureCube;
	typedef TD3D9Texture<IDirect3DTexture9,RRT_SharedTexture2D>	FD3D9SharedTexture2D;

	// Resources that directly map to D3D resources.
	template<typename D3DResourceType,ERHIResourceTypes ResourceTypeEnum> class TD3D9Resource : public D3DResourceType, public TFDynamicRHIResource<ResourceTypeEnum> {};

	typedef TD3D9Resource<IDirect3DVertexDeclaration9,RRT_VertexDeclaration>	FD3D9VertexDeclaration;
	typedef TD3D9Resource<IDirect3DVertexShader9,RRT_VertexShader>				FD3D9VertexShader;
	typedef TD3D9Resource<IDirect3DPixelShader9,RRT_PixelShader>				FD3D9PixelShader;
	typedef TD3D9Resource<IDirect3DIndexBuffer9,RRT_IndexBuffer>				FD3D9IndexBuffer;
	typedef TD3D9Resource<IDirect3DVertexBuffer9,RRT_VertexBuffer>				FD3D9VertexBuffer;
	typedef TD3D9Resource<Common::FRefCountedObject,RRT_SharedMemoryResource>	FD3D9SharedMemoryResource;
}